﻿using System;
using System.ComponentModel.DataAnnotations;
using System.Threading;

namespace Inovout.Data.Domain
{
    /// <summary>
    /// 持久化对象基类
    /// </summary>
    /// <typeparam name="TId"></typeparam>
    [Serializable]
    public abstract class DataObject : IEquatable<DataObject>
    {
        #region Field
        /// <summary>
        /// 主键
        /// </summary>
        private dynamic id;
        /// <summary>
        /// 创建时间
        /// </summary>
        private DateTime createdTime;
        /// <summary>
        /// 修改时间
        /// </summary>
        private DateTime modifiedTime;
        /// <summary>
        /// 访问时间
        /// </summary>
        private DateTime accessedTime;

        /// <summary>
        /// 创建者用户名
        /// </summary>
        private string createdUserName;
        /// <summary>
        /// 修改者用户名
        /// </summary>
        private string modifiedUserName;

        /// <summary>
        /// 访问者
        /// </summary>
        private string accessedUserName;
        /// <summary>
        /// 描述
        /// </summary>
        private string memo;

        /// <summary>
        /// 是否无效。如果为true，则表示逻辑无效，反之表示逻辑有效。
        /// </summary>
        private bool isInvalid;

        #endregion

        #region Public Property

        /// <summary>
        /// 主键。若需自主维护主键，可通过重写使其可写。
        /// </summary>
        [Alias("标识")]
        [DataType(DataType.Text)]
        public virtual dynamic Id
        {
            get { return id; }
            protected internal set { id = value; }
        }

        /// <summary>
        /// 创建时间
        /// </summary>
        [Alias("创建时间"),Display( Name ="创建时间")]
        public virtual DateTime CreatedTime
        {
            get { return createdTime; }
        }

        /// <summary>
        /// 修改时间
        /// </summary>
        [Alias("最后修改时间"), Display(Name = "最后修改时间")]
        public virtual DateTime ModifiedTime
        {
            get { return modifiedTime; }
        }

        /// <summary>
        /// 上一次访问时间
        /// </summary>
        [Alias("最后访问时间"), Display(Name = "最后访问时间")]
        public virtual DateTime? AccessedTime
        {
            get { return accessedTime; }
        }

        /// <summary>
        /// 创建者
        /// </summary>
        [Alias("创建用户名")]
        public virtual string CreatedUserName
        {
            get { return createdUserName; }
        }

        /// <summary>
        /// 上一次修改者
        /// </summary>
        [Alias("修改用户名")]
        public virtual string ModifiedUserName
        {
            get { return modifiedUserName; }
            internal protected set { modifiedUserName = value; }
        }

        /// <summary>
        /// 上一次访问者
        /// </summary>
        [Alias("访问用户名")]
        public virtual string AccessedUserName
        {
            get { return accessedUserName; }
            internal protected set { accessedUserName = value; }
        }

        /// <summary>
        /// 备忘录。允许在开发时，随意储存信息，通常为临时或应急处理数据。
        /// </summary>
        [Alias("备忘录")]
        public virtual string Memo
        {
            get { return memo; }
            set { memo = value; }
        }

        /// <summary>
        /// 是否是无效数据。默认为fase，表示有效数据。
        /// 同时，只能在继承的子类和同一程序集中赋值。
        /// </summary>
        [Alias("是否无效数据")]
        public virtual bool IsInvalid
        {
            get { return isInvalid; }
            internal protected set { isInvalid = value; }
        }

        #endregion

        #region Constructor

        protected DataObject(dynamic id)
             :this()
        {
            this.id = id;
        }
        /// <summary>
        /// 初始化DataObject
        /// </summary>
        protected DataObject()
        {
            //id = null;

            createdUserName = Thread.CurrentPrincipal.Identity.Name;
            modifiedUserName = createdUserName;
            accessedUserName = createdUserName;

            createdTime = DateTime.Now;
            modifiedTime = createdTime;
            accessedTime = createdTime;
        }

        #endregion

        #region Method

        protected internal virtual void SetModified(DateTime modifiedTime, string modifiedUserName = null)
        {
            this.modifiedTime = modifiedTime;
            this.modifiedUserName = modifiedUserName ?? Thread.CurrentPrincipal.Identity.Name;
        }

        /// <summary>
        /// 通过主键来比较两个对象是否相等。
        /// </summary>
        /// <param name="obj"></param>
        /// <returns>如果同一个实例或主键（不为默认值）相同，返回真，否则返回假。</returns>
        public override bool Equals(object obj)
        {
            return Equals(obj as DataObject);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="that"></param>
        /// <returns></returns>
        public virtual bool Equals(DataObject that)
        {
            //无论属性是否为IsUnique都是主键为准，如：名称相同，但主键不同，也视为不同对象。
            if (that == null)
            {
                return false;
            }
            if (DefaultValue.Is(this.Id) && DefaultValue.Is(that.Id))
            {
                return base.Equals(that);
            }
            else
            {
                return this.Id == that.Id;
            }
        }

        /// <summary>
        /// 默认使用主键的HashCode
        /// </summary>
        /// <returns>哈希代码</returns>
        public override int GetHashCode()
        {
            if (DefaultValue.Is((object)this.Id))
            {
                return base.GetHashCode();
            }
            return this.Id.GetHashCode();
        }

        #endregion

        private int version = 0;
        protected virtual int Version { get { return version; } }
        public virtual bool IsTransient
        {
            get { return DefaultValue.Is(this.id); }
        }


    }
}
